#include "fyp/core/MatrixUtil.h"

//------------------------------------------------------------------------------
// additional header includes

#define USE_D3DX

#ifdef USE_D3DX
	#include <d3dx9.h>
#endif

//------------------------------------------------------------------------------
namespace ming
{
namespace fyp
{
namespace core
{
	//--------------------------------------------------------------------------
	TMtx44 mtxLookAtLH(const TVec3 &eye, const TVec3 &target, const TVec3 &upDir)
	{
		TMtx44 out;

		TVec3 zaxis = target - eye;
		normalize(zaxis);

		TVec3 xaxis;
		cross(xaxis, upDir, zaxis);
		normalize(xaxis);

		TVec3 yaxis;
		cross(yaxis, zaxis, xaxis);
		normalize(yaxis);

		out.set(
			xaxis[0], yaxis[0], zaxis[0], 0.0f,
			xaxis[1], yaxis[1], zaxis[1], 0.0f,
			xaxis[2], yaxis[2], zaxis[2], 0.0f,
			-dot(xaxis, eye), -dot(yaxis, eye), -dot(zaxis, eye), 1.0f);

		return out;
	}

	//--------------------------------------------------------------------------
	TMtx44 mtxPerspectiveLH(float w, float h, float zNear, float zFar)
	{
		TMtx44 out;

#ifndef USE_D3DX
		float invDist = 1.0f / (zFar - zNear);

		out.set(
			2.0f * zNear / w, 0.0f, 0.0f, 0.0f,
			0.0f, 2.0f * zNear / h, 0.0f, 0.0f,
			0.0f, 0.0f, zFar * invDist, 1.0f,
			0.0f, 0.0f, -zNear * zFar * invDist, 0.0f);
#else

		D3DXMATRIX xMtx;
		D3DXMatrixPerspectiveLH(&xMtx, w, h, zNear, zFar);

		out.set(
			xMtx._11, xMtx._12, xMtx._13, xMtx._14,
			xMtx._21, xMtx._22, xMtx._23, xMtx._24,
			xMtx._31, xMtx._32, xMtx._33, xMtx._34,
			xMtx._41, xMtx._42, xMtx._43, xMtx._44);

#endif
		return out;
	}

	//--------------------------------------------------------------------------
	TMtx44 mtxPerspectiveFovLH(float fovy, float aspectRatio, float zNear, float zFar)
	{
		TMtx44 out;

#ifndef USE_D3DX
		float yScale = 1.0f / gmtl::Math::tan(fovy * 0.5f);
		float xScale = yScale / aspectRatio;
		float invDist = 1.0f / (zFar - zNear);

		out.set(
			xScale, 0.0f, 0.0f, 0.0f,
			0.0f, yScale, 0.0f, 0.0f,
			0.0f, 0.0f, zFar * invDist, 1.0f,
			0.0f, 0.0f, -zNear * zFar * invDist, 0.0f);
#else
		D3DXMATRIX xMtx;
		D3DXMatrixPerspectiveFovLH(&xMtx, fovy, aspectRatio, zNear, zFar);

		out.set(
			xMtx._11, xMtx._12, xMtx._13, xMtx._14,
			xMtx._21, xMtx._22, xMtx._23, xMtx._24,
			xMtx._31, xMtx._32, xMtx._33, xMtx._34,
			xMtx._41, xMtx._42, xMtx._43, xMtx._44);
#endif
		return out;
	}

	//--------------------------------------------------------------------------
	TMtx44 mtxRotateX(float angle)
	{
		TMtx44 out;

		float cosA = Math::cos(angle);
		float sinA = Math::sin(angle);

		out.set(
			1.0f, 0.0f, 0.0f, 0.0f,
			0.0f, cosA,-sinA, 0.0f,
			0.0f, sinA, cosA, 0.0f,
			0.0f, 0.0f, 0.0f, 1.0f);

		return out;
	}

	//--------------------------------------------------------------------------
	TMtx44 mtxRotateY(float angle)
	{
		TMtx44 out;

		float cosA = Math::cos(angle);
		float sinA = Math::sin(angle);

		out.set(
			cosA, 0.0f,-sinA, 0.0f,
			0.0f, 1.0f, 0.0f, 0.0f,
			sinA, 0.0f, cosA, 0.0f,
			0.0f, 0.0f, 0.0f, 1.0f);

		return out;
	}

	//--------------------------------------------------------------------------
	TMtx44 mtxRotateZ(float angle)
	{
		TMtx44 out;

		float cosA = Math::cos(angle);
		float sinA = Math::sin(angle);

		out.set(
			cosA,-sinA, 0.0f, 0.0f,
			sinA, cosA, 0.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
			0.0f, 0.0f, 0.0f, 1.0f);

		return out;
	}

	//--------------------------------------------------------------------------
	TMtx44 mtxTranslate(const TVec3 &trans)
	{
		TMtx44 out;

		out.set(
			1.0f, 0.0f, 0.0f, 0.0f,
			0.0f, 1.0f, 0.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
			trans[0], trans[1], trans[2], 1.0f);

		return out;
	}

	//--------------------------------------------------------------------------
	TMtx44 mtxTranslate(float tx, float ty, float tz)
	{
		return mtxTranslate( TVec3(tx, ty, tz) );
	}

	//--------------------------------------------------------------------------
	TMtx44 mtxScale(const TVec3 &scale)
	{
		TMtx44 out;

		out.set(
			scale[0], 0.0f, 0.0f, 0.0f,
			0.0f, scale[1], 0.0f, 0.0f,
			0.0f, 0.0f, scale[2], 0.0f,
			0.0f, 0.0f, 0.0f, 1.0f);

		return out;
	}

	//--------------------------------------------------------------------------
}
}
}